package com.martin.lib_base.ktx

import android.app.Activity
import com.google.gson.Gson
import com.martin.lib_base.net.NetApply
import dev.utils.DevFinal
import dev.utils.app.permission.PermissionUtils
import dev.utils.common.DateUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import org.json.JSONArray
import org.json.JSONObject
import java.util.*
import kotlin.coroutines.CoroutineContext

/**
 * @author：Houge
 * @date：2022/11/11
 * @desc：
 */
/********************************************************************************************
 *  String
 *********************************************************************************************/
/**
 * 非空处理
 * 空数据返回空字符串
 */
fun String?.noNull(replaceStr: String? = "") = this ?: replaceStr

/**
 * 验证是否为空数据
 */
fun Any?.verifyNullOrEmpty(msg: String): Boolean {
    var nullOrEmpty = this == null
    if (!nullOrEmpty && this is String) {
        nullOrEmpty = this.isEmpty()
    }
    if (nullOrEmpty) {
        normalToast(msg)
    }
    return nullOrEmpty
}


/********************************************************************************************
 *  Boolean
 *********************************************************************************************/
fun Boolean?.toInt() = if (this == true) 1 else 0

fun String?.toBoolean() = this == "1"

fun Int?.toBoolean() = this == 1
/********************************************************************************************
 *  Date
 *********************************************************************************************/

/**
 * 格式化日期
 */
fun Date?.formatDate(format: String = DevFinal.TIME.yyMMdd_HYPHEN): String {
    return this?.let { DateUtils.formatDate(it, format) } ?: ""
}

/**
 * 格式化日期时间
 */
fun Date?.formatDateTime(format: String = DevFinal.TIME.yyyyMMddHHmmss_HYPHEN): String {
    return this?.let { DateUtils.formatDate(it, format) } ?: ""
}

fun Long?.formatDateTime(format: String = DevFinal.TIME.yyyyMMddHHmmss_HYPHEN): String {
    return this?.let { DateUtils.formatTime(it, format) } ?: ""
}

fun Long?.formatDate(format: String = DevFinal.TIME.yyMMdd_HYPHEN): String {
    return this?.let { DateUtils.formatTime(it, format) } ?: ""
}

/********************************************************************************************
 *  Json
 *********************************************************************************************/

fun Any?.toJson(format: Boolean = true): String {
    if (this == null) {
        return "{}"
    }
    val json = NetApply.gson.toJson(this)

    // 不格式化直接返回
    if (!format) return json

    if (json.startsWith("{")) {
        return JSONObject(json).toString(2)
    } else if (json.startsWith("[")) {
        return JSONArray(json).toString(2)
    }
    return json
}

/********************************************************************************************
 *  倒计时
 *********************************************************************************************/

@OptIn(ExperimentalCoroutinesApi::class)
fun <T> countdown(
    duration: Long,
    interval: Long,
    context: CoroutineContext = Dispatchers.Default,
    onCountdown: suspend (Long) -> T
): Flow<T> =
    flow { (duration - interval downTo 0 step interval).forEach { emit(it) } }
        .onEach { delay(interval) }
        .onStart { emit(duration) }
        .flatMapMerge { flow { emit(onCountdown(it)) } }
        .flowOn(context)

/********************************************************************************************
 *  处理
 *********************************************************************************************/
/**
 *  虽然有空安全判定,但如果空与非空需要不同的处理,依然要做!=null判定
 *  该方法旨避免判空
 */
inline fun <T, R> T?.handle(handle: (T) -> R?, nullHandle: () -> R? = { null }): R? {
    return if (this != null) handle(this) else nullHandle()
}

/**
 * 尝试执行
 */
inline fun <T, R> T?.tryCatch(handle: (T?) -> R?, cacheHandle: () -> R? = { null }): R? {
    return try {
        handle(this)
    } catch (e: Exception) {
        cacheHandle()
    }
}

///////////////////////////////////////////////////////////////////////////
// 权限
///////////////////////////////////////////////////////////////////////////

/**
 * 申请权限
 */
fun Activity.permission(
    vararg permissions: String,
    onDenied: () -> Unit = {},
    onGranted: () -> Unit = {},
) {
    PermissionUtils.permission(*permissions)
        .callback(object : PermissionUtils.PermissionCallback {
            override fun onGranted() {
                onGranted()
            }

            override fun onDenied(
                grantedList: MutableList<String>?,
                deniedList: MutableList<String>?,
                notFoundList: MutableList<String>?
            ) {
                onDenied()
            }
        })
        .request(this)
}